﻿@using System.Diagnostics;
@inject IFileReaderService fileReaderService
@inject IJSRuntime CurrentJSRuntime
<h1>Hello, files!</h1>

Welcome to your new filestreaming app.
<br />
This demo reads a file without doing anything particular with it.
<br />
There are other demos in the menu.
<br />
<br />

<input type="file" @ref=inputElement />
<button @onclick=ReadFile class="btn btn-primary">Read file</button>
<button @onclick=ClearFile class="btn btn-primary">Clear</button>
<button @onclick=CancelFile disabled=@IsCancelDisabled class="btn btn-primary">Cancel</button>
<br />
<br />
<progress max="@max" value="@value" />
<br />
<textarea style="max-width: 100%;" cols="50" rows="20">@Output</textarea>
@code {
    private static string nl = Environment.NewLine;
    [Parameter]
    public int BufferSize { get; set; } = 20480;
    public long max;
    public long value;
    ElementReference inputElement;
    public System.Threading.CancellationTokenSource cancellationTokenSource;
    string Output { get; set; }

    public bool CanCancel { get; set; }
    public bool IsCancelDisabled => !CanCancel;

    public async Task ClearFile()
    {
        await fileReaderService.CreateReference(inputElement).ClearValue();
    }

    public async Task ReadFile()
    {
        max = 0;
        value = 0;
        Output = string.Empty;
        this.StateHasChanged();
        var files = await fileReaderService.CreateReference(inputElement).EnumerateFilesAsync();
        foreach (var file in files)
        {
            var fileInfo = await file.ReadFileInfoAsync();
            max = fileInfo.Size;

            var stopwatch = new Stopwatch();
            stopwatch.Start();

            Output += $"{nameof(IFileInfo)}.{nameof(fileInfo.Name)}: {fileInfo.Name}{nl}";
            Output += $"{nameof(IFileInfo)}.{nameof(fileInfo.Size)}: {fileInfo.Size}{nl}";
            Output += $"{nameof(IFileInfo)}.{nameof(fileInfo.Type)}: {fileInfo.Type}{nl}";
            Output += $"{nameof(IFileInfo)}.{nameof(fileInfo.LastModifiedDate)}: {fileInfo.LastModifiedDate?.ToString() ?? "(N/A)"}{nl}";
            foreach (var property in fileInfo.NonStandardProperties.Keys)
            {
                Output += $"{nameof(IFileInfo)}.{property} (nonstandard): {fileInfo.NonStandardProperties[property]}{nl}";
            }
            Output += $"Reading file...";
            this.StateHasChanged();
            Console.WriteLine(Output);
            cancellationTokenSource?.Dispose();
            cancellationTokenSource = new System.Threading.CancellationTokenSource();
            CanCancel = true;

            const int onlyReportProgressAfterThisPercentDelta = 10;

            // Subscribe to progress (change of position)
            fileInfo.PositionInfo.PositionChanged += (s, e) =>
            {
                // (optional) Only report progress in console / progress bar if percentage has moved over 10% since last call to Acknowledge()
                if (e.PercentageDeltaSinceAcknowledge > onlyReportProgressAfterThisPercentDelta)
                {
                    stopwatch.Stop();
                    Output += $"Read {(e.PositionDeltaSinceAcknowledge)} bytes ({e.Percentage:00}%). {e.Position} / {fileInfo.Size}{nl}";
                    this.InvokeAsync(this.StateHasChanged);
                    e.Acknowledge();
                    value = e.Position;
                    stopwatch.Start();
                }
            };

            try
            {
                // PositionStream is a stream created only for this demo, 
                // That does nothing with the data other then updating its position property.
                var ps = new PositionStream();

                using (var fs = await file.OpenReadAsync())
                {
                    await fs.CopyToAsync(ps, BufferSize, cancellationTokenSource.Token);
                    stopwatch.Stop();
                }

                value = max;
                Output += $"Done reading file {fileInfo.Name} - {fileInfo.Size} bytes in {stopwatch.ElapsedMilliseconds}ms.{nl}.";
                this.StateHasChanged();
            }
            catch (OperationCanceledException)
            {
                Output += $"Operation was cancelled";
                await InvokeAsync(StateHasChanged);
                await Task.Delay(1);
            }
            finally
            {
                CanCancel = false;
            }
        }



    }

    public async Task CancelFile()
    {
        Output += $"Cancel requested.{nl}";
        await InvokeAsync(StateHasChanged);
        await Task.Delay(1);
        cancellationTokenSource.Cancel();
    }

}




